package models;


import java.util.Arrays;

import models.msgs.*;
import models.msgs.Call;
import models.msgs.Number;
import play.Logger;
import play.mvc.*;
import play.libs.*;
import play.libs.F.*;
import akka.actor.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;


public class Human extends Player
{

    public final ActorRef             table;
    public ActorRef			  croupier;
    protected WebSocket.In<JsonNode>  in;
    protected WebSocket.Out<JsonNode> out;
    private int lastBet;

    public Human(String _name, WebSocket.In<JsonNode> _in,
            WebSocket.Out<JsonNode> _out, ActorRef _table)
    {
        name = _name;        
        table = _table;
        in = _in;
        out = _out;
        croupier = null;
        lastBet=0;
        numberOfWin=0;
        
        in.onMessage(new Callback<JsonNode>()
        {
            @Override
            public void invoke(JsonNode event)
            {
                try
                {
                	if (event.get("type").asText().equals("start")) {
                		table.tell(new Ready(name), getSelf());
                	} else if (event.get("type").asText().equals("cardstoexhange")) {
                		int quantityCards = 0;
                		for(int i = 0; i < 5; i++) {
                			if(event.get("card" + i).asInt() == 1) {
                				quantityCards++;
                			}
                		}
                		Karta[] cardsToExchange = new Karta[0];
                		if (quantityCards > 0) {
                			cardsToExchange = new Karta[quantityCards];
                			int j=0;
                    		for(int i = 0; i < 5; i++) {
                    			if (event.get("card" + i).asInt() == 1) {
                    				cardsToExchange[j] = cards[i];
                    				cards[i] = null;
                    				j++;
                    			}
                    		}
                		}
                    	table.tell(new CardsToExchange(cardsToExchange), getSelf());
                		

                		
                		
                	} else if (event.get("type").asText().equals("betting")) {
                		if(event.get("bettingOptions").asText().equals("bet")) {
                			croupier.tell(new Bet(name, event.get("heightofbet").asInt()), getSelf());
                			table.tell(new Info("Bet "+event.get("heightofbet").asInt(),name), getSelf());
                			myCash -= event.get("heightofbet").asInt();
                			updateCash();
        				} else if (event.get("bettingOptions").asText().equals("check")) {
        					croupier.tell(new Check(name), getSelf());
        					table.tell(new Info("Check",name), getSelf());
        				} else if (event.get("bettingOptions").asText().equals("raise")) {
        					croupier.tell(new Raise(name, event.get("heightofbet").asInt()), getSelf());
                			table.tell(new Info("Raise "+event.get("heightofbet").asInt(),name), getSelf());
                			myCash -= event.get("heightofbet").asInt();
                			updateCash();
        				} else if (event.get("bettingOptions").asText().equals("call")) {
        					croupier.tell(new Call(name,lastBet), getSelf());
                			table.tell(new Info("Call "+lastBet,name), getSelf());
                			myCash-=lastBet;
                			updateCash();
        				} else if (event.get("bettingOptions").asText().equals("allin")) {
        					croupier.tell(new AllIn(name,myCash), getSelf());
                			table.tell(new Info("All-in "+myCash,name), getSelf());
                			myCash = 0;
                			updateCash();
        				} else if (event.get("bettingOptions").asText().equals("fold")) {
        					croupier.tell(new Fold(name), getSelf());
                			table.tell(new Info("Fold",name), getSelf());
        				} if (event.get("type").asText().equals("options")) {
        					int buyin = event.get("startbuyin").asInt();
        					int cash = event.get("startcash").asInt();
        					int quantityOfBots = event.get("quantityofbots").asInt();;
        					int quantityOfHumans = event.get("quantityofhumans").asInt();;
        					
        					table.tell(new Options(quantityOfHumans, quantityOfHumans, quantityOfHumans, quantityOfHumans), getSelf());
                    	} if (event.get("type").asText().equals("quit")) {
        	       					
        					table.tell(new Quit(name), getSelf());
                    	}
        	
				} 
                		else {
                	
	              
                	}
                }
                catch (Exception e)
                {
                    Logger.error("invokeError"+ e.toString());
                    System.out.println(e.getStackTrace());
                }
                
            }
        });

        in.onClose(new Callback0()
        {
            @Override
            public void invoke()
            {
                table.tell(new Quit(name), getSelf() );
            }
        });
    }

    @Override
    public void preStart()
    {        
        String text = "my Actor is now running!";
    	table.tell(new Info(text, name), getSelf()); 
    }

    @Override
    public void postStop()
    {
        String text = "I've been killed";
    	table.tell(new Info(text, name), getSelf()); 
    }

    @Override
    public void onReceive(Object msg) throws Exception
    {
 
            if (msg instanceof Number)
            {   
            	int nr = ((Number) msg).getNumber();            	           			
            	String text = "I've got the number " + nr + " from WebSocket and send it to Table";
            	table.tell(new Info(text, name), getSelf()); 
            	table.tell(new Number(nr, name), getSelf());
            }  
            else if (msg instanceof Card)
            {
            	Card card = (Card) msg;    
            	String text = "I've got " + card.getRank() + " " + card.getColor() + " from Table" ;
            	table.tell(new Info(text, name), getSelf());  
            }            
            
            else if(msg instanceof Info)
            {        
            	Info info = (Info) msg;             	
	            ObjectNode event = Json.newObject();
	            event.put("type","message");
	            event.put("message", "[ "+ info.getName()+ " ] : " + info.getText()); 
	            
	            out.write(event);
            } else if(msg instanceof Cards) {
            	this.cards = ((Cards)msg).getCards();
            	Arrays.sort(this.cards);
            	ObjectNode event = Json.newObject();
            	event.put("type", "cards");
            	for (int i = 0; i < 5; i++ ) {
            		event.put("card"+i,this.cards[i].toString());
            	}
            	out.write(event);
            } else if(msg instanceof ExchangeCards) {
            	ObjectNode event = Json.newObject();
            	event.put("type","exchangecards");
            	out.write(event);
            } else if (msg instanceof CardsAfterExchange) {
            	CardsAfterExchange message = (CardsAfterExchange) msg;
            	updateCards(message.getCards());
            	table.tell(new Info("I echanged cards",name), getSelf());
            	//System.out.println(cards[0].toString() + " " +cards[1].toString()+ " " +cards[2].toString()+ " " +cards[3].toString()+ " " +cards[4].toString() );
            	ObjectNode eve = Json.newObject();
            	eve.put("type", "cards");
            	for (int i = 0; i < 5; i++ ) {
            		eve.put("card"+i,cards[i].toString());
            	}
            	
            	out.write(eve);
            }
            else if(msg instanceof Cash) {
            	myCash = ((Cash)msg).getCash();
            	updateCash();

            } else if(msg instanceof CollectBuyIn) {
            	croupier = getSender();
            	CollectBuyIn buyin = ((CollectBuyIn)msg);
            	myCash-=buyin.getBuyIn();
            	updateCash();
            	getSender().tell(new BuyIn(buyin.getBuyIn(),name), getSelf());
            } else if(msg instanceof Pot) {
            	int pot = ((Pot)msg).getPot();
            	updatePot(pot);
            } else if(msg instanceof OptionsOfBetting) {
            	OptionsOfBetting bo = (OptionsOfBetting)msg;
            	lastBet = bo.getLastBet();
            	updateLastBet(bo.getLastBet());
            	showBettingOptions(bo.getBettingOptions(),bo.getLastBet());
            	
            } else if(msg instanceof LastBet) {
            	updateLastBet(((LastBet) msg).getLastBet());
            } else if(msg instanceof Prize) {
            	Prize prize = (Prize)msg;
            	myCash+=prize.getPrize();
            	String tmp = "";
            	for (int i=0; i<5; i++){
            		tmp+=cards[i] + " ";
            	}
            	tmp+=SprawdzUklad.jakiUklad(cards);
            	table.tell(new Info("I won "+tmp,name), getSelf());
            	numberOfWin++;
            	updateCash(); 
            } else if(msg instanceof ShowMeCards) {
            	table.tell(new MyCards(name,cards), getSelf());
            } else if(msg instanceof AreYouBankrupt) {
            	Bankrupt bankrupt = new Bankrupt(name,myCash,numberOfWin);
            	table.tell(bankrupt, getSelf());
            } else if(msg instanceof GameOver) {
         	   ObjectNode event = Json.newObject();
        	   event.put("type", "gameover");
        	   out.write(event);
            }
            
            else {
                unhandled(msg);
            }
            
        }  
   private void updatePot(int pot) {
	   ObjectNode event = Json.newObject();
       event.put("type", "pula");
       event.put("pula", pot + "");
       out.write(event); 
   }
   private void updateCash() {
	   ObjectNode event = Json.newObject();
	   event.put("type", "cash");
	   event.put("cash", myCash + "");
	   out.write(event);
   }
   private void updateLastBet(int lastBet) {
	   ObjectNode event = Json.newObject();
	   event.put("type", "bet");
	   event.put("bet", lastBet + "");
	   out.write(event);
   }
   private void showBettingOptions(boolean[] bettingOptions,int lastBet) {
	   if(myCash <= lastBet) {
		   bettingOptions[2] = false;
		   bettingOptions[3] = false;
	   }
	   ObjectNode event = Json.newObject();
	   event.put("type","betoptions");
	   event.put("bet","" + (bettingOptions[0] == true ? 1 : 0));
	   event.put("check","" + (bettingOptions[1] == true ? 1 : 0));
	   event.put("raise","" + (bettingOptions[2] == true ? 1 : 0));
	   event.put("call","" + (bettingOptions[3] == true ? 1 : 0));
	   event.put("fold","" + (bettingOptions[4] == true ? 1 : 0));
	   event.put("allin","" + (bettingOptions[5] == true ? 1 : 0));
	   
	   out.write(event);
   }
            
}